package at.fhj.itm10.ticketmaster.services.impl;

import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import at.fhj.itm10.ticketmaster.dao.DAOException;
import at.fhj.itm10.ticketmaster.dao.EventDAO;
import at.fhj.itm10.ticketmaster.entities.Address;
import at.fhj.itm10.ticketmaster.entities.Event;
import at.fhj.itm10.ticketmaster.entities.EventType;
import at.fhj.itm10.ticketmaster.helper.Validator;
import at.fhj.itm10.ticketmaster.services.EventService;
import at.fhj.itm10.ticketmaster.services.ServiceException;

/**
 * {@inheritDoc}
 * 
 * @author Marvin Puchmüller, Benjamin Hirt, Gerald Hambrosch
 */
public class EventServiceImpl extends AbstractService implements EventService {

	
	private Logger logger = Logger.getLogger(EventServiceImpl.class);
	private List<Event> eventsl;
	private EventDAO eventdao;
	public EventDAO getEventdao() {
		return eventdao;
	}

	public void setEventdao(EventDAO eventdao) {
		this.eventdao = eventdao;
	}
	
	
	/**
	 * Inserts event into DB using EventDAO
	 * 
	 * @param event
	 * @throws ServiceException
	 * @return void
	 * 
	 * 
	 */
	public void insertEvent(Event event) {
		logger.debug("insertEvent()");
		Validator.notNullOrThrow(event, "event is null");		
		Validator.zeroOrThrow(event.getId(), "id for new event must be zero - will be autofilled");		
		
		try {
			
			getEventdao().insert(event);
			
		} catch (DAOException e) {
			//rollback();

			throw new ServiceException("Error on inserting data", e);
		} finally {
			//closeConnection();
		}
	}

	/**
	 * Updates event in DB (using EventDAO)
	 *  
	 * @param event
	 * @throws ServiceException
	 * @return void
	 * 
	 * 
	 */
	public void updateEvent(Event event) {
		logger.debug("updateEvent()");
		Validator.notNullOrThrow(event, "event is null");		
		Validator.notZeroOrThrow(event.getId(), "id needed for updating event");	

		try {
			begin();

			getEventdao().update(event);
			
			commit();
		} catch (DAOException e) {
			rollback();

			throw new ServiceException("Error on inserting data", e);
		} finally {
			closeConnection();
		}
		
	}

	/**
	 * Delete event from DB (using EventDAO)
	 * 
	 * @param event
	 * @throws ServiceException
	 * @return void
	 * 
	 * 
	 */
	public void deleteEvent(Event event) {
		logger.debug("deleteEvent()");
	
		try {
			begin();
		
			Validator.notNullOrThrow(event, "event is null");		
			Validator.notZeroOrThrow(event.getId(), "id needed for deleting event");
			getEventdao().delete(event);
			commit();
		} catch (Exception e) {
			rollback();
	
			throw new ServiceException("Error on inserting data", e);
		} finally {
			closeConnection();
		}
	}

	/**
	 * Searching event via id (using EventDAO)
	 *  
	 * @param id
	 * @throws ServiceException
	 * @return Event
	 * 
	 * 
	 */
	public Event findById(long id) {
		logger.debug("findById("+id+")");
		
		Event event = null;
		try
		{
			event = getEventdao().findById(id);
		}
        catch(DAOException e)
        {
            rollback();
			throw new ServiceException("Could not load EventDAO!", e);
        }
        finally
        {
            closeConnection();
        }
		return event;
	}

	/**
	 * Searching for all events (using EventDAO)
	 * 
	 * @throws ServiceException
	 * @return List<Event>
	 * 
	 * 
	 * 
	 */
	public List<Event> findAll() {
		logger.debug("findAll()");
		List<Event> events = null;
		try {
			begin();
			events = getEventdao().findAll();
			commit();
		} catch (DAOException e) {
			rollback();
			throw new ServiceException("FindAll() failed, probably DB-Connection-Error");
		} finally{
			closeConnection();
		}
		
		return events;
	}


	/**
	 *  Searching for all "top events" (using EventDAO)
	 *  
	 * @param id
	 * @throws ServiceException
	 * @return List<Event>
	 * 
	 * 
	 */
	public List<Event> findTopEvents() {
		List<Event> topevents = new ArrayList<Event>();
		topevents.addAll(getEventdao().findTopEvents());
		return topevents;
	}
	
	/**
	 * Searching for similar events via eventtype-id (using EventDAO)
	 * 
	 * @param id
	 * @throws ServiceException
	 * @throws SQLException
	 * @throws DAOException
	 * @return List<Event>
	 * 
	 * 
	 */
	public List<Event> findSameEvents(long id) throws DAOException, SQLException {
		List<Event> sameevents = new ArrayList<Event>();
		sameevents.addAll(getEventdao().findSameEvents(id));
		return sameevents;
	}

	/**
	 * Searching events via eventname (using EventTypeDAO)
	 *  
	 * @param eventname
	 * @throws ServiceException
	 * @return Event
	 * 
	 * 
	 */
	public List<Event> findByName(String eventname) {
		logger.debug("findByName("+eventname+")");
		
		List<Event> events = null;
		try
		{
			events = getEventdao().findByName(eventname);
		}
        catch(DAOException e)
        {
           // rollback();
			throw new ServiceException("Could not load EventDAO!", e);
        }
        finally
        {
           // closeConnection();
        }
		return events;
	}

	/**
	 * Searching for events via eventtype-id (using EventDAO)
	 * 
	 * @param c_id
	 * @throws ServiceException
	 * @return List<Event>
	 * 
	 * 
	 */
	public List<Event> findByCategory(long c_id) {
		logger.debug("findByCategory("+c_id+")");
		
		List<Event> events = null;
		try
		{
			events = getEventdao().findByCategory(c_id);
		}
        catch(DAOException e)
        {
            rollback();
			throw new ServiceException("Could not load EventDAO!", e);
        }
        finally
        {
            closeConnection();
        }
		return events;
	}

	/**
	 * Searching for events via start- and enddate (using EventDAO)
	 * 
	 * @param start, end
	 * @throws ParseException
	 * @throws ServiceException
	 * @return List<Event>
	 * 
	 * 
	 */
	public List<Event> findByDate(String start, String end) throws ParseException{
		logger.debug("findByDate("+start+" - "+end+")");

		Date endIn;
		Date startIn;
		SimpleDateFormat dFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		
			endIn = dFormat.parse(end);
			startIn = dFormat.parse(start);
			//logger.debug("findByDate()"+start+" or "+end+" are in the wrong format and can't be parsed");
			
		
		List<Event> events = null;
		try
		{
			events = getEventdao().findByDate(start, end);
		
		}
        catch(DAOException e)
        {
            rollback();
			throw new ServiceException("Could not load EventDAO!", e);
        }
        finally
        {
            closeConnection();
        }
		return events;
	}
	/**
	 * Searching event via address-id (using EventDAO)
	 * 
	 * @param id
	 * @throws ServiceException
	 * @return List<Event>
	 * 
	 * 
	 */
	public List<Event> findByAddress(long id) {
		logger.debug("findByAddress("+id+")");
		
		List<Event> events = null;
		try
		{
			events = getEventdao().findByAddress(id);
		}
        catch(DAOException e)
        {
            rollback();
			throw new ServiceException("Could not load EventDAO!", e);
        }
        finally
        {
            closeConnection();
        }
		return events;
	}

	/**
	 * Searching for random events (using EventDAO)
	 * 
	 * @throws ServiceException
	 * @return List<Event>
	 * 
	 * 
	 */
	public List<Event> findRandomEvents() {
		logger.debug("findRandomEvents()");
		
		List<Event> events = null;
		try
		{
			events = getEventdao().findRandomEvents();
		}
        catch(DAOException e)
        {
            rollback();
			throw new ServiceException("Could not load EventDAO!", e);
        }
        finally
        {
           closeConnection();
        }
		return events;
	}

	
	//Method to remove unique entries from a list
	/**
	 * Removing duplicate entries from a list
	 * 
	 * @param list
	 * @return void
	 * 
	 * 
	 */
	  public static void removeDuplicates(List<Event> list)  
	  {  
	    Set<Event> uniqueEntries = new HashSet<Event>();  
	    for (Iterator<Event> iter = list.iterator(); iter.hasNext(); ) {  
	      Event element = iter.next();  
	      if (!uniqueEntries.add(element))  
	        iter.remove();                
	    }  
	  } 
	
		/**
		 * Searching for events via name (using EventDAO)
		 * 
		 * @param namesearch
		 * @return List<Event>
		 *
		 * 
		 */
		public List<Event> doNormalSearch(String namesearch) {

			// clear last search
			//resetSearch();

			eventsl = new ArrayList<Event>();
		
			if ((namesearch != null) && (!namesearch.equals(""))) {
				
			
				// add events to eventslist
				List<Event> eventtmp = getEventdao().findByName(namesearch);
				for (Event e : eventtmp) {
					eventsl.add(e);

				}
			}	

			return eventsl;
				
		}

		/**
		 * Searching for events via address, category, start, end and (using EventTypeDAO)
		 * 
		 * @param address, category, start, end
		 * @return List<Event>
		 * 
		 * 
		 * 
		 */
	public List<Event> doExtendedSearch(Address address, EventType category,
			Date start, Date end) {
		// clear last search
		eventsl= new ArrayList<Event>();

		if (address != null) {
			List<Event> addresstmp = getEventdao().findByAddress(address.getId());
			for (Event e : addresstmp) {
				
				eventsl.add(e);

			}

		}
		if (category != null) {
			
			List<Event> categorytmp = getEventdao().findByCategory(category.getId());

			for (Event e : categorytmp) {
				eventsl.add(e);
			}
		}
		// if only start-date is set - start becomes the exact date to find
		if (end == null || start == null) {
			if(end == null)
			{	
				end = start;
			}
			if(start == null)
			{	
				start = end;
			}
		}
		
		if ((start != null) && (end != null)) {
				if(end.before(start))
				{
					Date tmpend;
					tmpend = start;
					start = end;
					end = tmpend;
				}
					// search for category
					SimpleDateFormat dFormat = new SimpleDateFormat(
							"yyyy-MM-dd HH:mm:ss");
					List<Event> dtmp;
					dtmp = getEventdao().findByDate(dFormat.format(start),
							dFormat.format(end));
	
					for (Event e : dtmp) 
					{
						eventsl.add(e);
					}
				
	
			}
		removeDuplicates(eventsl);
		return eventsl;
		}


	/**
	 * Searching for all events created by a customer via customer-id (using EventDAO)
	 * 
	 * @param id
	 * @return List<Event>
	 * 
	 * 
	 */
	public List<Event> findByCustomer(long id) {
	
		return getEventdao().findByCustomer(id);
	}

}